#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use std::os::raw::{c_char, c_void};

use melior::{
    Context,
    ir::{Value, ValueLike},
};
use mlir_sys::{MlirContext, MlirValue};

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

pub fn mlir_load_toy_dialect(context: &Context) {
    let raw_context = context.to_raw();
    unsafe {
        mlirLoadToyDialect(raw_context);
    }
}

pub struct ScopedHashTable {
    pub ptr: *mut c_void,
}
impl ScopedHashTable {
    pub fn new() -> Self {
        Self {
            ptr: unsafe { mlirScopedHashTableCreate() },
        }
    }
}
impl Drop for ScopedHashTable {
    fn drop(&mut self) {
        unsafe { mlirScopedHashTableDestroy(self.ptr) }
    }
}

pub struct ScopedHashTableScope {
    pub ptr: *const c_void,
}
impl<'a> ScopedHashTableScope {
    pub fn new(scoped_hash_table: &ScopedHashTable) -> Self {
        Self {
            ptr: unsafe { mlirScopedHashTableScopeCreate(scoped_hash_table.ptr) },
        }
    }
}
impl Drop for ScopedHashTableScope {
    fn drop(&mut self) {
        unsafe { mlirScopedHashTableScopeDestroy(self.ptr) }
    }
}

pub fn mlir_declare(scoped_hash_table: &ScopedHashTable, name: &str, value: Value) -> bool {
    let raw_value = value.to_raw();
    let result = unsafe {
        mlirDeclare(
            scoped_hash_table.ptr,
            name.as_ptr() as *const c_char,
            name.len(),
            raw_value,
        )
    };
    result == 1
}

pub fn mlir_lookup<'a>(scoped_hash_table: &ScopedHashTable, name: &str) -> Option<Value<'a, 'a>> {
    let raw_value: MlirValue = unsafe {
        mlirLookup(
            scoped_hash_table.ptr,
            name.as_ptr() as *const c_char,
            name.len(),
        )
    };
    if raw_value.ptr.is_null() {
        None
    } else {
        let value = unsafe { Value::from_raw(raw_value) };
        Some(value)
    }
}
